package org.sixtynine.stock.controller;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.sixtynine.stock.Constants.CommonData;
import org.sixtynine.stock.ReturnData;
import org.sixtynine.stock.dto.GridPramDTO;
import org.sixtynine.stock.dto.Page;
import org.sixtynine.stock.entity.BaseEntity;
import org.sixtynine.stock.entity.Company;
import org.sixtynine.stock.entity.SubSector;
import org.sixtynine.stock.entity.User;
import org.sixtynine.stock.model.FileUploadForm;
import org.sixtynine.stock.model.LoadingSearchCriteria;
import org.sixtynine.stock.service.CompanyService;
import org.sixtynine.stock.service.GenericService;
import org.sixtynine.stock.service.content.DataManagerService;
import org.sixtynine.stock.service.file.ExcelProcessorFactory;
import org.sixtynine.stock.service.file.FileDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author Thilanka
 * 
 */
@Controller
@SessionAttributes
public class CompanyController extends BackEndAuthController {

	private int RECORDS_PER_PAGE = 10;

	@Autowired
	private GenericService genericService;

	@Autowired
	private FileDataService fileDataService;

	@Autowired
	DataManagerService dataManagerService;

	@Autowired
	private CompanyService companyService;

	@RequestMapping(value = "/admin/company/search")
	public ModelAndView search(@ModelAttribute LoadingSearchCriteria criteria) {
		ModelAndView modelAndView = new ModelAndView("/admin/company/list");
		loadData(1, -1, criteria.getSectorId(), criteria.getSectorName(),
				criteria.getCompanyName(), criteria.getCompanyId(),
				modelAndView, criteria);

		return modelAndView;
	}

	@RequestMapping(value = "/admin/company/add")
	public ModelAndView addCompany(HttpServletRequest request,
			@ModelAttribute("uploadFile") FileUploadForm uploadFile) {
		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}

		modelAndView = new ModelAndView("/admin/company/add");
		modelAndView.addObject("company", new Company());
		bindSectors(modelAndView);
		bindSubSectors(modelAndView);
		modelAndView.addObject("userLogged", true);

		return modelAndView;
	}

	private void bindSubSectors(ModelAndView modelAndView) {
		List<BaseEntity> subSectorList = DataManagerService
				.getData(CommonData.SUB_SECTOR.toString());
		modelAndView.addObject("subSectorsMap", subSectorList);
	}

	private void bindSectors(ModelAndView modelAndView) {
		List<BaseEntity> sectorList = DataManagerService
				.getData(CommonData.SECTOR.toString());
		modelAndView.addObject("sectorsMap", sectorList);
	}

	@RequestMapping(value = "/admin/company/add/file_process")
	public ModelAndView addingCompaniesByFile(HttpServletRequest request,
			@ModelAttribute("uploadFile") FileUploadForm uploadFile) {

		ModelAndView modelAndView = null;

		modelAndView = new ModelAndView("/admin/company/list");

		List<BaseEntity> companies = DataManagerService
				.getData(CommonData.COMPANY.toString());
		modelAndView.addObject("companies", companies);

		MultipartFile multipartFile = uploadFile.getFile();
		ReturnData<String> fileSaveReturnData = fileDataService.saveFile(
				multipartFile, ExcelProcessorFactory.FILE_TYPE_COMPANY_LIST,
				null);

		StringBuilder message = new StringBuilder();
		if (fileSaveReturnData._isSuccess()) {
			// if success, process it
			ReturnData<List<? extends BaseEntity>> returnData = fileDataService
					.process(multipartFile.getOriginalFilename(),
							ExcelProcessorFactory.FILE_TYPE_COMPANY_LIST);
			if (returnData._isSuccess()) {
				message.append("file " + multipartFile.getOriginalFilename()
						+ " uploaded and inserted successfully");
				modelAndView.addObject("criteria", new LoadingSearchCriteria());
				// refresh data after insert
				dataManagerService.loadData(CommonData.COMPANY.toString(),
						Company.class);
			} else {
				message.append(returnData.getMsg());
			}
		} else {
			message.append(fileSaveReturnData.getMsg());
		}
		modelAndView.addObject("message", message);

		loadData(1, -1, -1, null, null, -1, modelAndView, null);
		return modelAndView;
	}

	private void addSelectedSubSectors(Integer[] subSectorIds, Company company) {
		Set<SubSector> subSectors = new HashSet<SubSector>();
		if (subSectorIds.length > 0 && (subSectorIds[0] > 0)) {
			for (int i = 0; i < subSectorIds.length; i++) {
				if (subSectorIds[i] > 0) {
					SubSector subSector = (SubSector) genericService.findById(
							subSectorIds[i], SubSector.class);
					if (subSector != null) {
						subSectors.add(subSector);
					}
				}
			}
			company.setSubSectors(subSectors);
		}
	}

	@RequestMapping(value = "/admin/company/add/process")
	public ModelAndView addingCompany(
			@ModelAttribute @Valid Company company,
			BindingResult result,
			@RequestParam(value = "subSectorId", required = false) Integer[] subSectorIds) {

		ModelAndView modelAndView = null;
		if (!result.hasErrors()) {
			addSelectedSubSectors(subSectorIds, company);
			genericService.saveOrUpdate(company);
			// refresh data after insert
			dataManagerService.loadData(CommonData.COMPANY.toString(),
					Company.class);
			modelAndView = new ModelAndView("/admin/company/list");
			modelAndView.addObject("criteria", new LoadingSearchCriteria());

			bindCompanies(modelAndView);

			String message = "Company was successfully added.";
			modelAndView.addObject("message", message);

		} else {
			modelAndView = new ModelAndView("/admin/company/add");
		}

		loadData(1, -1, -1, null, null, -1, modelAndView, null);

		return modelAndView;
	}

	private void bindCompanies(ModelAndView modelAndView) {
		List<BaseEntity> companies = DataManagerService
				.getData(CommonData.COMPANY.toString());
		modelAndView.addObject("companyMap", companies);

	}

	@RequestMapping(value = "/admin/company/list")
	public ModelAndView listOfCompany(
			HttpServletRequest request,
			@RequestParam(value = "page", required = false) Integer page,
			@RequestParam(value = "totalRecords", required = false) Integer totalRecords) {

		ModelAndView modelAndView = null;

		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}
		modelAndView = new ModelAndView("/admin/company/list");
		loadData(page, totalRecords, -1, null, null, -1, modelAndView, null);
		modelAndView.addObject("userLogged", true);

		return modelAndView;
	}

	/**
	 * load data
	 * 
	 * @param page
	 * @param totalRecords
	 * @param companyId
	 * @param fromDate
	 * @param toDate
	 * @param modelAndView
	 */
	private void loadData(Integer page, Integer totalRecords, int sectorId,
			String sectorName, String companyName, int companyId,
			ModelAndView modelAndView, LoadingSearchCriteria criteria) {
		GridPramDTO gridPramDTO = new GridPramDTO();
		gridPramDTO.setRows(RECORDS_PER_PAGE);
		if (page != null) {
			gridPramDTO.setPage(page);
		} else {
			gridPramDTO.setPage(1);
		}
		if (totalRecords != null) {
			gridPramDTO._setTotalNumberOfRecords(totalRecords);
		}

		if (companyId == 0) {
			companyId = -1;
		}
		if (sectorId == 0) {
			sectorId = -1;
		}

		Page<Company> companyPage = companyService.searchCompany(sectorId,
				sectorName, companyName, companyId, gridPramDTO);
		modelAndView.addObject("companyPage", companyPage);

		bindCompanies(modelAndView);
		bindSectors(modelAndView);
		bindSubSectors(modelAndView);

		// populate the search criteria from the session
		if (criteria != null) {
			companyId = criteria.getCompanyId();
			companyName = criteria.getCompanyName();
			sectorName = criteria.getSectorName();
			sectorId = criteria.getSectorId();
			// sectorName = criteria.getFromDate();
			// sectorId = criteria.getToDate();
		}

		if (criteria == null) {
			criteria = new LoadingSearchCriteria();
			criteria.setCompanyName(companyName);
			criteria.setCompanyId(companyId);
			criteria.setSectorName(sectorName);
			criteria.setSectorId(sectorId);

		}
		modelAndView.addObject("criteria", criteria);

	}

	@RequestMapping(value = "/admin/company/edit/{id}", method = RequestMethod.GET)
	public ModelAndView editCompany(HttpServletRequest request,
			@PathVariable Integer id) {
		ModelAndView modelAndView = null;
		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("admin/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}

		modelAndView = new ModelAndView("/admin/company/edit");

		BaseEntity company = genericService.findById(id, Company.class);
		modelAndView.addObject("company", company);

		bindSectors(modelAndView);
		bindSubSectors(modelAndView);
		modelAndView.addObject("userLogged", true);

		return modelAndView;
	}

	@RequestMapping(value = "/admin/company/edit/{id}", method = RequestMethod.POST)
	public ModelAndView edditingCompany(
			@ModelAttribute @Valid Company company,
			BindingResult result,
			@PathVariable Integer id,
			@RequestParam(value = "subSectorId", required = false) Integer[] subSectorIds,
			HttpServletRequest request) {

		ModelAndView modelAndView = null;
		if (!result.hasErrors()) {
			modelAndView = new ModelAndView("/admin/company/list");
			bindCompanies(modelAndView);
			addSelectedSubSectors(subSectorIds, company);
			genericService.saveOrUpdate(company);

			modelAndView.addObject("criteria", new LoadingSearchCriteria());
			// refresh data after insert
			dataManagerService.loadData(CommonData.COMPANY.toString(),
					Company.class);

			String message = "Company was successfully updated.";
			modelAndView.addObject("message", message);
			loadData(1, -1, -1, null, null, company.getId(), modelAndView, null);

		} else {
			modelAndView = new ModelAndView("/admin/company/edit");
			BaseEntity company1 = genericService.findById(id, Company.class);
			modelAndView.addObject("company", company1);

			List<BaseEntity> sectorList = DataManagerService
					.getData(CommonData.SECTOR.toString());
			modelAndView.addObject("sectorsMap", sectorList);

		}

		return modelAndView;
	}

	@RequestMapping(value = "/admin/company/delete/{id}", method = RequestMethod.GET)
	public ModelAndView deleteCompany(@PathVariable Integer id,
			HttpServletRequest request) {
		ModelAndView modelAndView = null;

		if (!isUserLogged(request)) {
			modelAndView = new ModelAndView("admin/login/login");
			modelAndView.addObject("registedUser", new User());
			return modelAndView;
		}
		genericService.delete(id, Company.class);
		modelAndView = new ModelAndView("/admin/company/list");
		modelAndView.addObject("criteria", new LoadingSearchCriteria());
		loadData(1, -1, -1, null, null, -1, modelAndView, null);

		String message = "Company was successfully deleted.";
		modelAndView.addObject("message", message);
		modelAndView.addObject("userLogged", true);
		return modelAndView;
	}

}
